//SPDX-FileCopyrightText: Copyright 2022-2024 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

package project_testcase_api_serv

import (
	"context"
	"time"

	"atomgit.com/openlinksaas-org/api-server/api_common"
	"atomgit.com/openlinksaas-org/api-server/dao"
	"atomgit.com/openlinksaas-org/api-server/dao/project_entry_dao"
	"atomgit.com/openlinksaas-org/api-server/dao/testcase_dao"
	"atomgit.com/openlinksaas-org/api-server/dao/user_dao"
	"atomgit.com/openlinksaas-org/api-server/utils"
	"atomgit.com/openlinksaas-org/proto-gen-go.git/notices/notices_testcase"
	"atomgit.com/openlinksaas-org/proto-gen-go.git/project_testcase_api"
	"github.com/google/uuid"
	"go.mongodb.org/mongo-driver/mongo"
)

func (apiImpl *ProjectTestCaseApiImpl) AddTestResult(ctx context.Context, req *project_testcase_api.AddTestResultRequest) (*project_testcase_api.AddTestResultResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_testcase_api.AddTestResultResponse{
			Code:   project_testcase_api.AddTestResultResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	projectItem, _, _, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_testcase_api.AddTestResultResponse{
			Code:   project_testcase_api.AddTestResultResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_testcase_api.AddTestResultResponse{
			Code:   project_testcase_api.AddTestResultResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}
	if projectItem.Closed {
		return &project_testcase_api.AddTestResultResponse{
			Code:   project_testcase_api.AddTestResultResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	//检查测试用例是否存在
	exist, err := testcase_dao.CaseInfoDao.Exist(ctx, req.CaseId, req.ProjectId)
	if err != nil {
		return nil, err
	}
	if !exist {
		return &project_testcase_api.AddTestResultResponse{
			Code:   project_testcase_api.AddTestResultResponse_CODE_NO_CASE,
			ErrMsg: "测试用例不存在",
		}, nil
	}
	//检查工作计划是否存在
	if req.SpritId != "" {
		exist, err = project_entry_dao.EntryDao.Exist(ctx, req.SpritId, req.ProjectId)
		if err != nil {
			return nil, err
		}
		if !exist {
			return &project_testcase_api.AddTestResultResponse{
				Code:   project_testcase_api.AddTestResultResponse_CODE_NO_SPIRT,
				ErrMsg: "工作计划不存在",
			}, nil
		}
	}

	testResultId := uuid.NewString()
	timeNow := time.Now().UnixNano() / 1e6

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = testcase_dao.ResultDao.Insert(sessCtx, &testcase_dao.TestResultInfoDbItem{
			TestResultId: testResultId,
			TestOk:       req.TestOk,
			CaseId:       req.CaseId,
			SpritId:      req.SpritId,
			ProjectId:    req.ProjectId,
			CreateUserId: sessionItem.UserId,
			CreateTime:   timeNow,
			UpdateUserId: sessionItem.UserId,
			UpdateTime:   timeNow,
		})
		if err != nil {
			return nil, err
		}
		err = dao.MsgDataDao.Insert(sessCtx, &dao.MsgDataDBItem{
			MsgId:        testResultId,
			Content:      req.Content,
			CreateUserId: sessionItem.UserId,
			CreateTime:   timeNow,
			HasChanged:   false,
		})
		if err != nil {
			return nil, err
		}
		//更新结果计数
		count, err := testcase_dao.ResultDao.Count(sessCtx, req.ProjectId, req.CaseId, false, "")
		if err != nil {
			return nil, err
		}
		err = testcase_dao.CaseInfoDao.UpdateResultCount(sessCtx, req.CaseId, req.ProjectId, count)
		if err != nil {
			return nil, err
		}
		if req.SpritId != "" {
			count, err := testcase_dao.ResultDao.Count(sessCtx, req.ProjectId, req.CaseId, true, req.SpritId)
			if err != nil {
				return nil, err
			}
			err = testcase_dao.LinkSpritDao.UpdateResultCount(sessCtx, req.CaseId, req.SpritId, count)
			if err != nil {
				return nil, err
			}
		}
		return &project_testcase_api.AddTestResultResponse{
			Code:         project_testcase_api.AddTestResultResponse_CODE_OK,
			TestResultId: testResultId,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	//发送通知
	go api_common.SendNoticeToProjectScope(context.Background(), req.ProjectId, &notices_testcase.UpdateCaseNotice{
		ProjectId: req.ProjectId,
		CaseId:    req.CaseId,
	})
	return ret.(*project_testcase_api.AddTestResultResponse), nil
}

func (apiImpl *ProjectTestCaseApiImpl) UpdateTestResult(ctx context.Context, req *project_testcase_api.UpdateTestResultRequest) (*project_testcase_api.UpdateTestResultResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_testcase_api.UpdateTestResultResponse{
			Code:   project_testcase_api.UpdateTestResultResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_testcase_api.UpdateTestResultResponse{
			Code:   project_testcase_api.UpdateTestResultResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_testcase_api.UpdateTestResultResponse{
			Code:   project_testcase_api.UpdateTestResultResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}
	if projectItem.Closed {
		return &project_testcase_api.UpdateTestResultResponse{
			Code:   project_testcase_api.UpdateTestResultResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	resultItem, err := testcase_dao.ResultDao.Get(ctx, req.ProjectId, req.TestResultId)
	if err != nil {
		return &project_testcase_api.UpdateTestResultResponse{
			Code:   project_testcase_api.UpdateTestResultResponse_CODE_NO_TEST_RESULT,
			ErrMsg: "测试结果不存在",
		}, nil
	}

	if !(projectItem.OwnerUserId == sessionItem.UserId || roleItem.BasicInfo.Admin || resultItem.CreateUserId == sessionItem.UserId) {
		return &project_testcase_api.UpdateTestResultResponse{
			Code:   project_testcase_api.UpdateTestResultResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	timeNow := time.Now().UnixNano() / 1e6

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = testcase_dao.ResultDao.UpdateTestOk(sessCtx, req.ProjectId, req.TestResultId, req.TestOk, sessionItem.UserId, timeNow)
		if err != nil {
			return nil, err
		}
		err = dao.MsgDataDao.Update(sessCtx, req.TestResultId, req.Content)
		if err != nil {
			return nil, err
		}
		return &project_testcase_api.UpdateTestResultResponse{
			Code: project_testcase_api.UpdateTestResultResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	//发送通知
	go api_common.SendNoticeToProjectScope(context.Background(), req.ProjectId, &notices_testcase.UpdateCaseNotice{
		ProjectId: req.ProjectId,
		CaseId:    resultItem.CaseId,
	})
	return ret.(*project_testcase_api.UpdateTestResultResponse), nil
}

func (apiImpl *ProjectTestCaseApiImpl) ListTestResult(ctx context.Context, req *project_testcase_api.ListTestResultRequest) (*project_testcase_api.ListTestResultResponse, error) {
	emptyList := []*project_testcase_api.TestResultInfo{}

	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_testcase_api.ListTestResultResponse{
			Code:       project_testcase_api.ListTestResultResponse_CODE_WRONG_SESSION,
			ErrMsg:     "会话不存在",
			ResultList: emptyList,
		}, nil
	}
	_, _, _, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_testcase_api.ListTestResultResponse{
			Code:       project_testcase_api.ListTestResultResponse_CODE_NO_PROJECT,
			ErrMsg:     "项目不存在",
			ResultList: emptyList,
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_testcase_api.ListTestResultResponse{
			Code:       project_testcase_api.ListTestResultResponse_CODE_NO_PERMISSION,
			ErrMsg:     "没有权限",
			ResultList: emptyList,
		}, nil
	} else if err != nil {
		return nil, err
	}

	caseItem, err := testcase_dao.CaseInfoDao.Get(ctx, req.CaseId, req.ProjectId)
	if err != nil {
		return &project_testcase_api.ListTestResultResponse{
			Code:       project_testcase_api.ListTestResultResponse_CODE_NO_CASE,
			ErrMsg:     "测试用例不存在",
			ResultList: emptyList,
		}, nil
	}

	count, err := testcase_dao.ResultDao.Count(ctx, req.ProjectId, req.CaseId, req.FilterBySpritId, req.SpritId)
	if err != nil {
		return nil, err
	}
	resultItemList, err := testcase_dao.ResultDao.List(ctx, req.ProjectId, req.CaseId, req.FilterBySpritId, req.SpritId, int64(req.Offset), int64(req.Limit))
	if err != nil {
		return nil, err
	}

	spritIdList := []string{}
	userIdList := []string{}
	resultIdList := []string{}
	for _, resultItem := range resultItemList {
		if resultItem.SpritId != "" {
			spritIdList = append(spritIdList, resultItem.SpritId)
		}
		userIdList = append(userIdList, resultItem.CreateUserId)
		userIdList = append(userIdList, resultItem.UpdateUserId)
		resultIdList = append(resultIdList, resultItem.TestResultId)
	}

	//获取用户信息
	userItemList, err := user_dao.UserInfoDao.ListById(ctx, userIdList)
	if err != nil {
		return nil, err
	}
	userItemMap := map[string]*user_dao.UserInfoDbItem{}
	for _, userItem := range userItemList {
		userItemMap[userItem.UserId] = userItem
	}

	//获取工作计划信息
	entryItemList, err := project_entry_dao.EntryDao.ListById(ctx, spritIdList)
	if err != nil {
		return nil, err
	}
	entryItemMap := map[string]*project_entry_dao.EntryInfoDbItem{}
	for _, entryItem := range entryItemList {
		entryItemMap[entryItem.EntryId] = entryItem
	}

	//获取测试结果内容
	contentItemList, err := dao.MsgDataDao.ListById(ctx, resultIdList)
	if err != nil {
		return nil, err
	}
	contentItemMap := map[string]*dao.MsgDataDBItem{}
	for _, contentItem := range contentItemList {
		contentItemMap[contentItem.MsgId] = contentItem
	}
	//生成结果
	resultList := []*project_testcase_api.TestResultInfo{}
	for _, resultItem := range resultItemList {
		result := resultItem.ToTestResultInfo()
		createUser, ok := userItemMap[resultItem.CreateUserId]
		if ok {
			result.CreateDisplayName = createUser.BasicInfo.DisplayName
			result.CreateLogoUri = createUser.BasicInfo.LogoUri
		}
		updateUser, ok := userItemMap[resultItem.UpdateUserId]
		if ok {
			result.UpdateDisplayName = updateUser.BasicInfo.DisplayName
			result.UpdateLogoUri = updateUser.BasicInfo.LogoUri
		}
		entryItem, ok := entryItemMap[result.SpritId]
		if ok {
			result.SpritTitle = entryItem.EntryTitle
		}
		result.CaseTitle = caseItem.Title
		contentItem, ok := contentItemMap[resultItem.TestResultId]
		if ok {
			result.Content = contentItem.Content
		}
		resultList = append(resultList, result)
	}

	return &project_testcase_api.ListTestResultResponse{
		Code:       project_testcase_api.ListTestResultResponse_CODE_OK,
		Count:      count,
		ResultList: resultList,
	}, nil
}

func (apiImpl *ProjectTestCaseApiImpl) RemoveTestResult(ctx context.Context, req *project_testcase_api.RemoveTestResultRequest) (*project_testcase_api.RemoveTestResultResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_testcase_api.RemoveTestResultResponse{
			Code:   project_testcase_api.RemoveTestResultResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_testcase_api.RemoveTestResultResponse{
			Code:   project_testcase_api.RemoveTestResultResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_testcase_api.RemoveTestResultResponse{
			Code:   project_testcase_api.RemoveTestResultResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}
	if projectItem.Closed {
		return &project_testcase_api.RemoveTestResultResponse{
			Code:   project_testcase_api.RemoveTestResultResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	resultItem, err := testcase_dao.ResultDao.Get(ctx, req.ProjectId, req.TestResultId)
	if err != nil { //记录不存在
		return &project_testcase_api.RemoveTestResultResponse{
			Code: project_testcase_api.RemoveTestResultResponse_CODE_OK,
		}, nil
	}

	if !(projectItem.OwnerUserId == sessionItem.UserId || roleItem.BasicInfo.Admin || resultItem.CreateUserId == sessionItem.UserId) {
		return &project_testcase_api.RemoveTestResultResponse{
			Code:   project_testcase_api.RemoveTestResultResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = testcase_dao.ResultDao.Remove(sessCtx, req.ProjectId, req.TestResultId)
		if err != nil {
			return nil, err
		}
		err = dao.MsgDataDao.Remove(sessCtx, req.TestResultId)
		if err != nil {
			return nil, err
		}
		//更新结果计数
		count, err := testcase_dao.ResultDao.Count(sessCtx, req.ProjectId, resultItem.CaseId, false, "")
		if err != nil {
			return nil, err
		}
		err = testcase_dao.CaseInfoDao.UpdateResultCount(sessCtx, resultItem.CaseId, req.ProjectId, count)
		if err != nil {
			return nil, err
		}
		if resultItem.SpritId != "" {
			count, err := testcase_dao.ResultDao.Count(sessCtx, req.ProjectId, resultItem.CaseId, true, resultItem.SpritId)
			if err != nil {
				return nil, err
			}
			err = testcase_dao.LinkSpritDao.UpdateResultCount(sessCtx, resultItem.CaseId, resultItem.SpritId, count)
			if err != nil {
				return nil, err
			}
		}
		return &project_testcase_api.RemoveTestResultResponse{
			Code: project_testcase_api.RemoveTestResultResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	//发送通知
	go api_common.SendNoticeToProjectScope(context.Background(), req.ProjectId, &notices_testcase.UpdateCaseNotice{
		ProjectId: req.ProjectId,
		CaseId:    resultItem.CaseId,
	})
	return ret.(*project_testcase_api.RemoveTestResultResponse), nil
}
